/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package predictor.gui.dataviewer;

import java.util.HashSet;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;
import weka.core.Attribute;
import weka.core.Instance;
import weka.core.Instances;

/**
 *
 * @author Administrator
 */
public class DataTableModel implements TableModel {

    private HashSet m_Listeners;
    private Instances m_Data;
    private int m_minRows;
    private int m_minCols;
    private int m_numInstances;
    private int m_numAttributes;
    private int m_numCols;
    private int m_numRows;

    public DataTableModel(int c, int r) {
        m_Listeners = new HashSet();
        m_minCols = c;
        m_minRows = r;
        m_numInstances = 0;
        m_numAttributes = 0;
        m_numCols = c;
        m_numRows = r;
        m_Data = null;
    }

    public void setInstances(Instances data) {
        if(data==null) return;
//        if (data.classIndex() == -1) {
//            data.setClassIndex(data.numAttributes() - 1);
//        }
        m_Data = data;
        m_numInstances = m_Data.numInstances();
        m_numAttributes = m_Data.numAttributes();
        m_numCols = m_minCols > m_numAttributes ? m_minCols : m_numAttributes;
        m_numRows = m_minRows > m_numInstances ? m_minRows : m_numInstances;
    }

    @Override
    public Class getColumnClass(int column) {
        Class result = null;
        if ((column < 0) && (column >= m_numCols)) {
            return result;
        }
        if (column >= m_numAttributes) {
            result = String.class;
        } else {
            if (getType(column) == Attribute.NUMERIC) {
                result = Double.class;
            } else {
                result = String.class;   // otherwise no input of "?"!!!
            }
        }
        return result;
    }

    public int getType(int columnIndex) {
        return getType(0, columnIndex);
    }

    public int getType(int rowIndex, int columnIndex) {
        int result;

        result = Attribute.STRING;

        if ((rowIndex >= 0) && (rowIndex < m_numRows)
                && (columnIndex >= 0) && (columnIndex < m_numCols)) {
            result = m_Data.instance(rowIndex).attribute(columnIndex).type();
        }

        return result;
    }

    public boolean isMissingAt(int rowIndex, int columnIndex) {
        boolean result;

        result = false;

        if ((rowIndex >= 0) && (rowIndex < m_numInstances)
                && (columnIndex > 0) && (columnIndex < m_numAttributes)) {
            result = (m_Data.instance(rowIndex).isMissing(columnIndex));
        }

        return result;
    }

    public int getRowCount() {
        return m_numRows;
    }

    public int getColumnCount() {
        return m_numCols;
    }

    @Override
    public String getColumnName(int columnIndex) {
        String result = null;
        if (columnIndex >= m_numAttributes) {
            result = "变 量";
        } else {
            result = "<html><center>";
            // name
            if (columnIndex == m_Data.classIndex()) {
                result += "<b>"
                        + m_Data.attribute(columnIndex).name()
                        + "</b>";
            } else {
                result += m_Data.attribute(columnIndex).name();
            }
            result += "</center></html>";
        }
        return result;
    }

    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex) {
//        if (rowIndex >= m_numInstances || columnIndex >= m_numAttributes) {
//            return false;
//        } else {
//            return true;
//        }
        return false;
    }

    public Object getValueAt(int rowIndex, int columnIndex) {
        if (rowIndex < 0 || rowIndex >= m_numRows || columnIndex < 0 || columnIndex >= m_numCols) {
            return null;
        } else if (rowIndex >= m_numInstances || columnIndex >= m_numAttributes) {
            return null;
        } else {
            Object result;
            String tmp;

            result = null;

            if (isMissingAt(rowIndex, columnIndex)) {
                result = null;
            } else {
                switch (getType(columnIndex)) {
                    case Attribute.DATE:
                    case Attribute.NOMINAL:
                    case Attribute.STRING:
                    case Attribute.RELATIONAL:
                        result = m_Data.instance(rowIndex).stringValue(columnIndex);
                        break;
                    case Attribute.NUMERIC:
                        result = new Double(m_Data.instance(rowIndex).value(columnIndex));
                        break;
                    default:
                        result = "-can't display-";
                }
            }

            if (getType(columnIndex) != Attribute.NUMERIC) {
                if (result != null) {
                    // does it contain "\n" or "\r"? -> replace with red html tag
                    tmp = result.toString();
                    if ((tmp.indexOf("\n") > -1) || (tmp.indexOf("\r") > -1)) {
                        tmp = tmp.replaceAll("\\r\\n", "<font color=\"red\"><b>\\\\r\\\\n</b></font>");
                        tmp = tmp.replaceAll("\\r", "<font color=\"red\"><b>\\\\r</b></font>");
                        tmp = tmp.replaceAll("\\n", "<font color=\"red\"><b>\\\\n</b></font>");
                        result = "<html>" + tmp + "</html>";
                    }
                }
            }

            return result;
        }
    }

    @Override
    public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
        if (rowIndex >= m_numInstances || columnIndex >= m_numAttributes) {
            return;
        } else {
            int type;
            int index;
            String tmp;
            Instance inst;
            Attribute att;
            Object oldValue;

//    if (!m_IgnoreChanges)
//      addUndoPoint();

            oldValue = getValueAt(rowIndex, columnIndex);
            type = getType(rowIndex, columnIndex);
            index = columnIndex;
            inst = m_Data.instance(rowIndex);
            att = inst.attribute(index);

            // missing?
            if (aValue == null) {
                inst.setValue(index, Instance.missingValue());
            } else {
                tmp = aValue.toString();

                switch (type) {
                    case Attribute.DATE:
                        try {
                            att.parseDate(tmp);
                            inst.setValue(index, att.parseDate(tmp));
                        } catch (Exception e) {
                            // ignore
                        }
                        break;

                    case Attribute.NOMINAL:
                        if (att.indexOfValue(tmp) > -1) {
                            inst.setValue(index, att.indexOfValue(tmp));
                        }
                        break;

                    case Attribute.STRING:
                        inst.setValue(index, tmp);
                        break;

                    case Attribute.NUMERIC:
                        try {
                            Double.parseDouble(tmp);
                            inst.setValue(index, Double.parseDouble(tmp));
                        } catch (Exception e) {
                            // ignore
                        }
                        break;

                    case Attribute.RELATIONAL:
                        try {
                            inst.setValue(index, inst.attribute(index).addRelation((Instances) aValue));
                        } catch (Exception e) {
                            // ignore
                        }
                        break;

                    default:
                        throw new IllegalArgumentException("Unsupported Attribute type: " + type + "!");
                }
            }

//    // notify only if the value has changed!
//    if (notify && (!("" + oldValue).equals("" + aValue)) )
//        notifyListener(new TableModelEvent(this, rowIndex, columnIndex));
        }
    }

    public void addTableModelListener(TableModelListener l) {
        m_Listeners.add(l);
    }

    public void removeTableModelListener(TableModelListener l) {
        m_Listeners.remove(l);
    }

    public int getM_numAttributes() {
        return m_numAttributes;
    }

    public int getM_numInstances() {
        return m_numInstances;
    }

    public Instances getInstances() {
        return m_Data;
    }
}
